package com.pwt.service;

import com.pwt.common.CustomException;
import com.pwt.common.DataNotFoundException;
import com.pwt.common.ResultCode;
import com.pwt.common.ResultPage;
import com.pwt.entity.*;
import com.pwt.model.MenuTreeModel;
import com.pwt.model.RoleGrantsModel;
import com.pwt.repository.*;
import com.pwt.security.utils.JWTUtils;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.QueryFactory;
import com.querydsl.core.types.Projections;
import com.querydsl.jpa.impl.JPAQueryFactory;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.criterion.Distinct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * Role service层
 *
 * @author auto generated
 * @date 2021-08-27 15:18:32
 */
@Service
public class RoleService {
    @Autowired
    RoleRepository repository;

    @Autowired
    JPAQueryFactory queryFactory;

    @Autowired
    RoleMenuRepository roleMenuRepository;

    @Autowired
    UserRoleRepository userRoleRepository;

    @Autowired
    MenuRepository menuRepository;
    
    @Autowired
    RoleMachineRepository roleMachineRepository;

    public Role add(Role role) throws CustomException {
        String sign = role.getSign();
        Set<String> menus = role.getMenus();
        int count = repository.countBySign(sign);
        if(count > 0) {
            throw new CustomException(ResultCode.DATA_EXISTED);
        }
        Role saved = repository.save(role);
        if(menus != null && !menus.isEmpty()) {
            String roleId = saved.getId();
            for(String menu:menus) {
                RoleMenu roleMenu = new RoleMenu();
                roleMenu.setRoleId(roleId);
                roleMenu.setMenuId(menu);
                roleMenuRepository.save(roleMenu);
            }
        }

        String manchines= role.getManchines();
        List<RoleMachine> list = new ArrayList<>();
        if(StringUtils.isNotBlank(manchines)){
            for (String maschine:manchines.split(",")) {
                if(maschine != null){
                    RoleMachine roleMachine = new RoleMachine();
                    roleMachine.setRoleId(saved.getId());
                    roleMachine.setMachineId(Integer.parseInt(maschine));
                    list.add(roleMachine);
                }
            }
            roleMachineRepository.saveAll(list);
        }
        return saved;
    }

    public ResultPage<Role> list(Integer page, Integer limit, String name) {
        ResultPage<Role> resultPage = new ResultPage<>();
        QRole qRole = QRole.role;

        QRoleMachine qRoleMachine = QRoleMachine.roleMachine;
        QMASCHINE qMachine = QMASCHINE.mASCHINE;
        BooleanBuilder booleanBuilder = new BooleanBuilder();
        if(StringUtils.isNotBlank(name)){
            booleanBuilder.and(qRole.name.like(name));
        }

        long count = queryFactory.select(qRole.count()).from(qRole).where(booleanBuilder).fetchOne();
        if(count == 0) {
            return resultPage;
        }
        List<Role> list = queryFactory.select(qRole).from(qRole).where(booleanBuilder).limit(limit).offset((page - 1) * limit).fetch();
        if(list != null && list.size() > 0 ){
            for (Role r:list) {
                List<MASCHINE> maschineList= queryFactory.select(qMachine).from(qRoleMachine).leftJoin(qMachine).on(qRoleMachine.machineId.eq(qMachine.mAMASCHINE))
                        .where(qRoleMachine.roleId.eq(r.getId())).fetch();

                String mancines = "";
                for (int i = 0; i < maschineList.size(); i++) {
                    if(i == (maschineList.size()-1)){
                        mancines = mancines+maschineList.get(i).getMAMASCHINE();
                    }else{
                        mancines = mancines+maschineList.get(i).getMAMASCHINE()+",";
                    }
                }
                r.setManchines(mancines);
            }
        }

        resultPage.setCurrentPage(page);
        resultPage.setTotalRow(count);
        resultPage.setPageSize(limit);
        resultPage.setData(list);
        resultPage.setTotalPage((int) (count/limit) + 1);
        return resultPage;
    }

    public Role role(String id) throws DataNotFoundException {
        Optional<Role> optional = repository.findById(id);
        if(!optional.isPresent()) {
            throw new DataNotFoundException(ResultCode.DATA_NOT_FOUND);
        }

        QRoleMachine qRoleMachine = QRoleMachine.roleMachine;
        QMASCHINE qMachine = QMASCHINE.mASCHINE;
        Role role=  optional.get();
        if (role != null && role.getId() != null) {
            List<MASCHINE> maschineList= queryFactory.select(qMachine).from(qRoleMachine).leftJoin(qMachine).on(qRoleMachine.machineId.eq(qMachine.mAMASCHINE))
                    .where(qRoleMachine.roleId.eq(role.getId())).fetch();
            String mancines = "";
            for (int i = 0; i < maschineList.size(); i++) {
                if(i == (maschineList.size()-1)){
                    mancines = mancines+maschineList.get(i).getMAMASCHINE();
                }else{
                    mancines = mancines+maschineList.get(i).getMAMASCHINE()+",";
                }
            }
            role.setManchines(mancines);
        }
        return role;
    }

    @Transactional(rollbackFor = Exception.class)
    public Role edit(Role role) throws CustomException {
        String sign = role.getSign();
        Set<String> menus = role.getMenus();
        Role role1 = repository.findBySign(sign);
        if(role1 != null) {
            if(!role1.getId().equals(role.getId())) {
                throw new CustomException(ResultCode.DATA_EXISTED);
            }
        }
        Role saved = repository.save(role);
        if(menus != null && !menus.isEmpty()) {
            String roleId = saved.getId();
            for(String menu:menus) {
                RoleMenu roleMenu = new RoleMenu();
                roleMenu.setRoleId(roleId);
                roleMenu.setMenuId(menu);
                roleMenuRepository.save(roleMenu);
            }
        }
        this.roleMachineRepository.deleteByRoleId(role.getId());
        List<RoleMachine> list = new ArrayList<>();
        String manchines = role.getManchines();
        if(StringUtils.isNotBlank(manchines)){
            for (String maschine:manchines.split(",")) {
                if(maschine != null){
                    RoleMachine roleMachine = new RoleMachine();
                    roleMachine.setRoleId(saved.getId());
                    roleMachine.setMachineId(Integer.parseInt(maschine));
                    list.add(roleMachine);
                }
            }
            roleMachineRepository.saveAll(list);
        }
        return saved;
    }

    @Transactional(rollbackFor = Exception.class)
    public String delete(String id) {
        roleMenuRepository.deleteByRoleId(id);
        userRoleRepository.deleteByRoleId(id);
        repository.deleteById(id);
        return id;
    }

    @Transactional(rollbackFor = Exception.class)
    public void grants(RoleGrantsModel roleGrantsModel) {
        String roleId = roleGrantsModel.getRoleId();
        List<String> menuIds = roleGrantsModel.getMenuIds();
        roleMenuRepository.deleteByRoleId(roleId);
        for(String menuId:menuIds) {
            RoleMenu roleMenu = new RoleMenu();
            roleMenu.setRoleId(roleId);
            roleMenu.setMenuId(menuId);
            roleMenuRepository.save(roleMenu);
        }
    }

    public MenuTreeModel menus(String id) {
        MenuTreeModel abstractModel = new MenuTreeModel();
        abstractModel.setName("虚拟节点");
        QMenu qMenu = QMenu.menu;
        QRoleMenu qRoleMenu = QRoleMenu.roleMenu;
        List<Menu> checked = queryFactory.select(qMenu).from(qMenu).leftJoin(qRoleMenu).on(qMenu.id.eq(qRoleMenu.menuId)).where(qRoleMenu.roleId.eq(id)).fetch();
        List<Menu> menus = menuRepository.findAll(Sort.by(Sort.Order.asc("sortNumber")));
        for(Menu menu:menus) {
            if(checked.contains(menu)) {
                menu.setChecked(true);
            }
        }
        List<Menu> first = menus.stream().filter(menu -> menu.getLevel() == 0).collect(Collectors.toList());
        List<Menu> second = menus.stream().filter(menu -> menu.getLevel() == 1).collect(Collectors.toList());
        List<Menu> third = menus.stream().filter(menu -> menu.getLevel() == 2).collect(Collectors.toList());
        List<MenuTreeModel> firstMenu = new ArrayList<>();
        for(Menu menu:first) {
            firstMenu.add(new MenuTreeModel(menu));
        }
        abstractModel.setChildren(firstMenu);
        for(MenuTreeModel model:firstMenu) {
            List<MenuTreeModel> secondMenu = new ArrayList<>();
            for(Menu menu : second) {
                if(model.getId().equals(menu.getParentId())) {
                    secondMenu.add(new MenuTreeModel(menu));
                }
            }
            model.setChildren(secondMenu);
            for(MenuTreeModel sModel:secondMenu) {
                List<MenuTreeModel> thirdMenu = new ArrayList<>();
                for(Menu menu : third) {
                    if(sModel.getId().equals(menu.getParentId())) {
                        thirdMenu.add(new MenuTreeModel(menu));
                    }
                }
                sModel.setChildren(thirdMenu);
            }
        }
        return abstractModel;
    }


    public MenuTreeModel getMenusByUser() {
        String username = JWTUtils.getToken().getUsername();
        Set<String> roles = this.repository.getByUsername(username);

        MenuTreeModel abstractModel = new MenuTreeModel();
        abstractModel.setName("虚拟节点");
        QMenu qMenu = QMenu.menu;
        QRoleMenu qRoleMenu = QRoleMenu.roleMenu;
        List<Menu> checked = queryFactory.select(qMenu).distinct().from(qMenu).leftJoin(qRoleMenu).on(qMenu.id.eq(qRoleMenu.menuId)).where(qRoleMenu.roleId.in(roles)).orderBy(qMenu.sortNumber.asc()).fetch();

        for(Menu menu:checked) {
            menu.setChecked(true);
        }
        List<Menu> first = checked.stream().filter(menu -> menu.getLevel() == 0).collect(Collectors.toList());
        List<Menu> second = checked.stream().filter(menu -> menu.getLevel() == 1).collect(Collectors.toList());
        List<Menu> third = checked.stream().filter(menu -> menu.getLevel() == 2).collect(Collectors.toList());
        List<MenuTreeModel> firstMenu = new ArrayList<>();
        for(Menu menu:first) {
            firstMenu.add(new MenuTreeModel(menu));
        }
        abstractModel.setChildren(firstMenu);
        for(MenuTreeModel model:firstMenu) {
            List<MenuTreeModel> secondMenu = new ArrayList<>();
            for(Menu menu : second) {
                if(model.getId().equals(menu.getParentId())) {
                    secondMenu.add(new MenuTreeModel(menu));
                }
            }
            model.setChildren(secondMenu);
            for(MenuTreeModel sModel:secondMenu) {
                List<MenuTreeModel> thirdMenu = new ArrayList<>();
                for(Menu menu : third) {
                    if(sModel.getId().equals(menu.getParentId())) {
                        thirdMenu.add(new MenuTreeModel(menu));
                    }
                }
                sModel.setChildren(thirdMenu);
            }
        }
        return abstractModel;
    }
}
